package ofdinv

import (
	"fmt"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
)

// TransportParser 货物运输发票解析器
type TransportParser struct {
	ofdReader *OFDReader
}

// NewTransportParser 创建新的货物运输发票解析器
func NewTransportParser(reader *OFDReader) *TransportParser {
	return &TransportParser{
		ofdReader: reader,
	}
}

// Parse 解析货物运输发票
func (p *TransportParser) Parse() (*InvoiceInfo, error) {
	doc, err := p.ofdReader.ParseDocument()
	if err != nil {
		return nil, fmt.Errorf("解析Document.xml失败: %v", err)
	}
	// 解析CustomTag.xml内容
	customTagRoot, err := p.ofdReader.ParseCustomTagTransport(doc)
	if err != nil {
		return nil, fmt.Errorf("获取CustomTag内容失败: %v", err)
	}

	pages := doc.Pages.Page
	var allTextObjectsWithPosition []TextObjectWithPosition
	var allGoodsInfos []TransportGoodsInfo
	var allTransportInfos []TransportDetail

	for _, page := range pages {
		// 获取页面内容
		pagePath := filepath.Join("Doc_0", page.BaseLoc)
		var pageXml Page
		if err := p.ofdReader.ReadXMLFile(pagePath, &pageXml); err != nil {
			return nil, fmt.Errorf("读取页面XML失败 (路径 %s): %v", pagePath, err)
		}
		currentPageObjs := pageXml.GetAllTextObject()

		// 获取模板内容
		tplPath := filepath.Join("Doc_0", doc.GetTplBaseLocByID(pageXml.Template.TemplateID))
		var tplXml TplPageContent
		if err := p.ofdReader.ReadXMLFile(tplPath, &tplXml); err != nil {
			return nil, fmt.Errorf("读取模板XML失败 (路径 %s): %v", tplPath, err)
		}

		// 获取分区边界
		goodsY := tplXml.GetBoundary("项目名称").Y
		transportY := tplXml.GetBoundary("运输工具种类").Y
		totalY := tplXml.GetBoundary("价税合计（大写）").Y

		// 获取当前页面的文本对象
		pageTextObjectsWithPosition := p.GetTextObjectWithPosition(page.ID, currentPageObjs)

		// 分区当前页面的文本对象
		tempGoodsArea, tempTransportArea := p.partitionTextObjectsByY(pageTextObjectsWithPosition, goodsY, transportY, totalY)

		// 获取当前页面的字段边界
		goodsFieldBounds := p.getGoodsFieldBoundaries(tplXml)
		transportFieldBounds := p.getTransportFieldBoundaries(tplXml)

		// 解析当前页面的商品信息
		pageGoodsInfos := p.parseGoodsInfoForPage(tempGoodsArea, goodsFieldBounds)
		allGoodsInfos = append(allGoodsInfos, pageGoodsInfos...)

		// 解析当前页面的运输信息
		pageTransportInfos := p.parseTransportInfoForPage(tempTransportArea, transportFieldBounds)
		// 合并多行运输信息
		mergedTransportInfos := p.mergeMultiLineFields(pageTransportInfos)
		allTransportInfos = append(allTransportInfos, mergedTransportInfos...)

		// 收集所有文本对象用于通用字段解析
		allTextObjectsWithPosition = append(allTextObjectsWithPosition, pageTextObjectsWithPosition...)
	}
	// 将商品信息转换为标准VATItem格式
	items := p.convertTransportGoodsToVATItems(allGoodsInfos)

	// 构建发票基本信息
	invoiceInfo := &InvoiceInfo{
		Type:             InvoiceTypeTransport,
		Items:            items,
		TransportDetails: p.convertTransportDetails(allTransportInfos),
	}

	// 解析通用字段（发票号码、开票时间、购销双方信息、合计金额、合计税额、开票人）
	invoiceInfo.InvoiceNumber = p.getFieldTextFromCustomTag(customTagRoot.InvoiceNo, allTextObjectsWithPosition)
	invoiceInfo.InvoiceDate = p.getFieldTextFromCustomTag(customTagRoot.IssueDate, allTextObjectsWithPosition)
	invoiceInfo.BuyerName = p.getFieldTextFromCustomTag(customTagRoot.Buyer.BuyerName, allTextObjectsWithPosition)
	invoiceInfo.BuyerTaxID = p.getFieldTextFromCustomTag(customTagRoot.Buyer.BuyerTaxID, allTextObjectsWithPosition)
	invoiceInfo.SellerName = p.getFieldTextFromCustomTag(customTagRoot.Seller.SellerName, allTextObjectsWithPosition)
	invoiceInfo.SellerTaxID = p.getFieldTextFromCustomTag(customTagRoot.Seller.SellerTaxID, allTextObjectsWithPosition)
	invoiceInfo.TotalAmount = p.getFieldTextFromCustomTag(customTagRoot.TaxExclusiveTotalAmount, allTextObjectsWithPosition)
	invoiceInfo.TotalTax = p.getFieldTextFromCustomTag(customTagRoot.TaxTotalAmount, allTextObjectsWithPosition)
	invoiceInfo.TotalAmountWithTax = p.getFieldTextFromCustomTag(customTagRoot.TaxInclusiveTotalAmount, allTextObjectsWithPosition)
	invoiceInfo.Drawer = p.getFieldTextFromCustomTag(customTagRoot.InvoiceClerk, allTextObjectsWithPosition)
	invoiceInfo.Note = p.getFieldTextFromCustomTag(customTagRoot.Note, allTextObjectsWithPosition)

	return invoiceInfo, nil
}

func (p *TransportParser) GetTextObjectWithPosition(pageID int, textObjects []TextObject) []TextObjectWithPosition {
	var objosition []TextObjectWithPosition
	for _, obj := range textObjects {
		var temoObjosition TextObjectWithPosition
		temoObjosition.TextID = obj.ID
		temoObjosition.PageID = pageID
		temoObjosition.X = obj.Boundary.X + obj.TextCode.X
		temoObjosition.Y = obj.Boundary.Y + obj.TextCode.Y
		temoObjosition.Width = obj.Size + obj.TextCode.DeltaX.Sum()
		temoObjosition.Height = obj.Boundary.H
		temoObjosition.Text = obj.TextCode.Text
		objosition = append(objosition, temoObjosition)
	}
	return objosition
}

// partitionTextObjectsByY 根据基准Y坐标将TextObject分为商品信息和运输信息
func (p *TransportParser) partitionTextObjectsByY(textObjects []TextObjectWithPosition, goodsY, transportY, totalY float64) ([]TextObjectWithPosition, []TextObjectWithPosition) {
	const tolerance = 2.0 // Y坐标容差范围
	var goodsArea, transportArea []TextObjectWithPosition
	for i := range textObjects {
		obj := &textObjects[i]
		// 判断属于商品信息区域
		if obj.Y >= goodsY-tolerance && obj.Y <= transportY {
			obj.Area = "goods"
			goodsArea = append(goodsArea, *obj)
		} else if obj.Y > transportY && obj.Y < totalY+tolerance {
			// 判断属于运输信息区域
			obj.Area = "transport"
			transportArea = append(transportArea, *obj)
		}
	}
	return goodsArea, transportArea
}

// getGoodsFieldBoundaries 获取商品信息字段的边界信息
func (p *TransportParser) getGoodsFieldBoundaries(tplXml TplPageContent) *GoodsFieldBoundaries {
	bounds := &GoodsFieldBoundaries{}

	// 获取字段标签的边界信息
	measurementUnitBoundary := tplXml.GetBoundary("单 位")
	quantityBoundary := tplXml.GetBoundary("数 量")
	unitPriceBoundary := tplXml.GetBoundary("单 价")
	amountBoundary := tplXml.GetBoundary("金 额")
	taxRateBoundary := tplXml.GetBoundary("税率/征收率")
	taxAmountBoundary := tplXml.GetBoundary("税 额")

	// 设置字段边界（考虑容差）
	const tolerance = 1.0
	fontSize := tplXml.GetItemFontSize()

	// 项目名称：从0开始到"单位"左边
	bounds.ItemNameLeft = 0
	bounds.ItemNameRight = measurementUnitBoundary.X - tolerance

	// 单位：在"单位"标签范围内
	bounds.MeasurementUnitLeft = bounds.ItemNameRight
	bounds.MeasurementUnitRight = measurementUnitBoundary.X + fontSize*3 + tolerance

	// 数量：在"数量"标签范围内
	bounds.QuantityLeft = bounds.MeasurementUnitRight
	bounds.QuantityRight = quantityBoundary.X + fontSize*3 + tolerance

	// 单价：在"单价"标签范围内
	bounds.UnitPriceLeft = bounds.QuantityRight
	bounds.UnitPriceRight = unitPriceBoundary.X + fontSize*3 + tolerance

	// 金额：在"金额"标签范围内
	bounds.AmountLeft = bounds.UnitPriceRight
	bounds.AmountRight = amountBoundary.X + fontSize*3 + tolerance

	// 税率：在"税率/征收率"标签范围内
	bounds.TaxRateLeft = bounds.AmountRight
	bounds.TaxRateRight = taxRateBoundary.X + fontSize*6 + tolerance

	// 税额：在"税额"标签范围内
	bounds.TaxAmountLeft = bounds.TaxRateRight
	bounds.TaxAmountRight = taxAmountBoundary.X + fontSize*3 + tolerance

	return bounds
}

// getGoodsFieldBoundaries 获取运输信息字段的边界信息
func (p *TransportParser) getTransportFieldBoundaries(tplXml TplPageContent) *TransportFieldBoundaries {
	bounds := &TransportFieldBoundaries{}
	// 设置字段边界（考虑容差）
	const tolerance = 0.5
	// 获取字段标签的边界信息
	// vehicleTypeBoundary := tplXml.GetBoundary("运输工具种类")
	// vehicleNumberBoundary := tplXml.GetBoundary("运输工具牌号")
	// departureBoundary := tplXml.GetBoundary("起运地")
	// destinationBoundary := tplXml.GetBoundary("到达地")
	// cargoNameBoundary := tplXml.GetBoundary("运输货物名称")
	// fontSize := tplXml.GetItemFontSize()

	//运输工具种类
	bounds.VehicleTypeLeft = 0
	bounds.VehicleTypeRight = bounds.VehicleTypeLeft + 40
	//运输工具牌号
	bounds.VehicleNumberLeft = bounds.VehicleTypeRight + tolerance
	bounds.VehicleNumberRight = bounds.VehicleNumberLeft + 40
	//起运地
	bounds.DepartureLeft = bounds.VehicleNumberRight + tolerance
	bounds.DepartureRight = bounds.DepartureLeft + 42
	//到达地
	bounds.DestinationLeft = bounds.DepartureRight + tolerance
	bounds.DestinationRight = bounds.DestinationLeft + 42
	//运输货物名称
	bounds.CargoNameLeft = bounds.DestinationRight + tolerance
	bounds.CargoNameRight = bounds.CargoNameLeft + 37

	return bounds

}

// parseGoodsInfoForPage 解析单个页面的商品信息（基于字段边界）
func (p *TransportParser) parseGoodsInfoForPage(goodsArea []TextObjectWithPosition, bounds *GoodsFieldBoundaries) []TransportGoodsInfo {
	// 按Y坐标分组（同一行的TextObject）
	rows := p.groupByYCoordinate(goodsArea, 2.0) // 2.0的Y坐标容差

	var goodsInfos []TransportGoodsInfo

	for _, row := range rows {
		// 跳过包含"¥"符号的行（可能是合计行）
		hasCurrency := false
		for _, obj := range row {
			if strings.Contains(obj.Text, "¥") {
				hasCurrency = true
				break
			}
		}
		if hasCurrency {
			continue
		}

		// 使用字段边界匹配算法解析单行
		goodsInfo := p.parseGoodsRowWithBoundaries(row, bounds)

		// 只有当有项目名称时才认为是有效商品行
		if goodsInfo.ItemName != "" {
			goodsInfos = append(goodsInfos, goodsInfo)
		}
	}

	return goodsInfos
}

// parseGoodsRowWithBoundaries 使用字段边界解析单行商品信息
func (p *TransportParser) parseGoodsRowWithBoundaries(row []TextObjectWithPosition, bounds *GoodsFieldBoundaries) TransportGoodsInfo {
	goodsInfo := TransportGoodsInfo{}

	// 根据字段边界匹配每个文本对象
	for _, obj := range row {
		x := obj.X
		text := obj.Text

		// 项目名称匹配
		if x >= bounds.ItemNameLeft && x <= bounds.ItemNameRight && goodsInfo.ItemName == "" {
			goodsInfo.ItemName = text
			obj.FieldType = "item_name"
			continue
		}

		// 单位匹配
		if x >= bounds.MeasurementUnitLeft && x <= bounds.MeasurementUnitRight && goodsInfo.MeasurementUnit == "" {
			goodsInfo.MeasurementUnit = text
			obj.FieldType = "measurement_unit"
			continue
		}

		// 数量匹配
		if x >= bounds.QuantityLeft && x <= bounds.QuantityRight && goodsInfo.Quantity == "" {
			goodsInfo.Quantity = text
			obj.FieldType = "quantity"
			continue
		}

		// 单价匹配
		if x >= bounds.UnitPriceLeft && x <= bounds.UnitPriceRight && goodsInfo.UnitPrice == "" {
			goodsInfo.UnitPrice = text
			obj.FieldType = "unit_price"
			continue
		}

		// 金额匹配
		if x >= bounds.AmountLeft && x <= bounds.AmountRight && goodsInfo.Amount == "" {
			goodsInfo.Amount = text
			obj.FieldType = "amount"
			continue
		}

		// 税率匹配
		if x >= bounds.TaxRateLeft && x <= bounds.TaxRateRight && goodsInfo.TaxRate == "" {
			goodsInfo.TaxRate = text
			obj.FieldType = "tax_rate"
			continue
		}

		// 税额匹配
		if x >= bounds.TaxAmountLeft && goodsInfo.TaxAmount == "" {
			goodsInfo.TaxAmount = text
			obj.FieldType = "tax_amount"
			continue
		}
	}

	return goodsInfo
}

// parseTransportInfoForPage 解析单个页面的运输信息（基于字段边界）
func (p *TransportParser) parseTransportInfoForPage(transportArea []TextObjectWithPosition, bounds *TransportFieldBoundaries) []TransportDetail {
	// 按Y坐标分组（同一行的TextObject）
	rows := p.groupByYCoordinate(transportArea, 2.0) // 2.0的Y坐标容差

	var transportInfos []TransportDetail

	for _, row := range rows {
		// 使用字段边界匹配算法解析单行
		transportInfo := p.parseTransportRowWithBoundaries(row, bounds)

		// 只要有任一运输相关信息（车辆类型、货物名称、起运地、到达地）就认为是有效运输行
		if transportInfo.VehicleType != "" || transportInfo.VehicleNumber != "" || transportInfo.CargoName != "" ||
			transportInfo.Departure != "" || transportInfo.Destination != "" {
			transportInfos = append(transportInfos, transportInfo)
		}
	}

	return transportInfos
}

// parseTransportRowWithBoundaries 使用字段边界解析单行运输信息
func (p *TransportParser) parseTransportRowWithBoundaries(row []TextObjectWithPosition, bounds *TransportFieldBoundaries) TransportDetail {
	transportInfo := TransportDetail{}

	// 根据字段边界匹配每个文本对象
	for _, obj := range row {
		x := obj.X
		text := obj.Text

		// 运输工具种类匹配
		if x >= bounds.VehicleTypeLeft && x <= bounds.VehicleTypeRight && transportInfo.VehicleType == "" {
			transportInfo.VehicleType = text
			obj.FieldType = "vehicle_type"
			continue
		}

		// 运输工具牌号匹配
		if x >= bounds.VehicleNumberLeft && x <= bounds.VehicleNumberRight && transportInfo.VehicleNumber == "" {
			transportInfo.VehicleNumber = text
			obj.FieldType = "vehicle_number"
			continue
		}

		// 起运地匹配
		if x >= bounds.DepartureLeft && x <= bounds.DepartureRight && transportInfo.Departure == "" {
			transportInfo.Departure = text
			obj.FieldType = "departure"
			continue
		}

		// 到达地匹配
		if x >= bounds.DestinationLeft && x <= bounds.DestinationRight && transportInfo.Destination == "" {
			transportInfo.Destination = text
			obj.FieldType = "destination"
			continue
		}

		// 运输货物名称匹配
		if x >= bounds.CargoNameLeft && x <= bounds.CargoNameRight && transportInfo.CargoName == "" {
			transportInfo.CargoName = text
			obj.FieldType = "cargo_name"
			continue
		}
	}

	return transportInfo
}

// groupByYCoordinate 按Y坐标分组TextObject
func (p *TransportParser) groupByYCoordinate(objects []TextObjectWithPosition, tolerance float64) [][]TextObjectWithPosition {
	if len(objects) == 0 {
		return nil
	}

	// 先按Y坐标排序
	sort.Slice(objects, func(i, j int) bool {
		if objects[i].Y == objects[j].Y {
			return objects[i].X < objects[j].X
		}
		return objects[i].Y < objects[j].Y
	})

	var groups [][]TextObjectWithPosition
	currentGroup := []TextObjectWithPosition{objects[0]}

	for i := 1; i < len(objects); i++ {
		// 如果Y坐标在容差范围内，认为是同一行
		if mathAbs(objects[i].Y-objects[i-1].Y) <= tolerance {
			currentGroup = append(currentGroup, objects[i])
		} else {
			groups = append(groups, currentGroup)
			currentGroup = []TextObjectWithPosition{objects[i]}
		}
	}

	// 添加最后一组
	if len(currentGroup) > 0 {
		groups = append(groups, currentGroup)
	}

	return groups
}

// mergeMultiLineFields 合并多行运输信息
func (p *TransportParser) mergeMultiLineFields(transportInfos []TransportDetail) []TransportDetail {
	if len(transportInfos) <= 1 {
		return transportInfos
	}

	var mergedInfos []TransportDetail
	var currentValidInfo *TransportDetail

	for i := range transportInfos {
		currentInfo := &transportInfos[i]

		// 如果运输工具种类为空，则合并到上一个有效信息
		if currentInfo.VehicleType == "" && currentValidInfo != nil {
			// 合并起运地信息（使用空格分隔）
			if currentInfo.Departure != "" {
				if currentValidInfo.Departure != "" {
					currentValidInfo.Departure += " " + currentInfo.Departure
				} else {
					currentValidInfo.Departure = currentInfo.Departure
				}
			}

			// 合并到达地信息（使用空格分隔）
			if currentInfo.Destination != "" {
				if currentValidInfo.Destination != "" {
					currentValidInfo.Destination += " " + currentInfo.Destination
				} else {
					currentValidInfo.Destination = currentInfo.Destination
				}
			}

			// 合并货物名称信息（使用空格分隔）
			if currentInfo.CargoName != "" {
				if currentValidInfo.CargoName != "" {
					currentValidInfo.CargoName += " " + currentInfo.CargoName
				} else {
					currentValidInfo.CargoName = currentInfo.CargoName
				}
			}

			// 合并运输工具牌号信息（使用空格分隔）
			if currentInfo.VehicleNumber != "" {
				if currentValidInfo.VehicleNumber != "" {
					currentValidInfo.VehicleNumber += " " + currentInfo.VehicleNumber
				} else {
					currentValidInfo.VehicleNumber = currentInfo.VehicleNumber
				}
			}
		} else {
			// 当前行有运输工具种类，作为新的有效信息
			mergedInfos = append(mergedInfos, *currentInfo)
			currentValidInfo = &mergedInfos[len(mergedInfos)-1]
		}
	}

	return mergedInfos
}

// convertTransportGoodsToVATItems 将运输发票商品信息转换为VATItem格式
func (p *TransportParser) convertTransportGoodsToVATItems(transportGoods []TransportGoodsInfo) []VATItem {
	var items []VATItem

	for _, tg := range transportGoods {
		// 转换数值字段，忽略转换错误，使用默认值0
		quantity, _ := strconv.ParseFloat(tg.Quantity, 64)
		unitPrice, _ := strconv.ParseFloat(tg.UnitPrice, 64)
		amount, _ := strconv.ParseFloat(tg.Amount, 64)
		taxAmount, _ := strconv.ParseFloat(tg.TaxAmount, 64)

		item := VATItem{
			Name:      tg.ItemName,
			Spec:      "", // 运输发票没有规格型号
			Unit:      tg.MeasurementUnit,
			Quantity:  quantity,
			UnitPrice: unitPrice,
			Amount:    amount,
			TaxRate:   tg.TaxRate,
			TaxAmount: taxAmount,
		}

		items = append(items, item)
	}

	return items
}

// convertTransportDetails 将TransportDetail转换为TransportDetails
func (p *TransportParser) convertTransportDetails(transportDetails []TransportDetail) []TransportDetails {
	var details []TransportDetails

	for _, td := range transportDetails {
		detail := TransportDetails{
			VehicleType:   td.VehicleType,
			VehicleNumber: td.VehicleNumber,
			Departure:     td.Departure,
			Destination:   td.Destination,
			CargoName:     td.CargoName,
		}
		details = append(details, detail)
	}

	return details
}

// getFieldTextFromCustomTag 根据CustomTag字段引用获取对应的文本内容
func (p *TransportParser) getFieldTextFromCustomTag(field ObjectRefField, textObjects []TextObjectWithPosition) string {
	var texts []string

	for _, objRef := range field.ObjectRefs {
		// 在文本对象中查找匹配的PageID和TextID
		for _, textObj := range textObjects {
			if textObj.PageID == objRef.PageRef {
				// 将对象ID字符串转换为整数进行比较
				objID, err := strconv.Atoi(objRef.Text)
				if err == nil && textObj.TextID == objID {
					texts = append(texts, textObj.Text)
					break // 找到匹配的对象后跳出内层循环
				}
			}
		}
	}

	// 如果有多个文本，用空格连接
	if len(texts) > 0 {
		result := ""
		for i, text := range texts {
			if i > 0 {
				result += " "
			}
			result += text
		}
		return result
	}

	return ""
}

// math.Abs 的简单实现，用于处理浮点数绝对值
func mathAbs(x float64) float64 {
	if x < 0 {
		return -x
	}
	return x
}
